#!perl
use strict;
use Data::Dumper;
use DBI;
use Cwd 'abs_path';
use File::Basename;

my $mydir = abs_path(dirname($0));

my $sqlite;
if (-e '/usr/local/bin/sqlite3') {
    $sqlite = '/usr/local/bin/sqlite3';
}
elsif (-e '/usr/bin/sqlite3') {
    $sqlite = '/usr/bin/sqlite3';
}
if (-e "$mydir/sqlite3-freebsd-captive/sqlite") {
    $sqlite = "$mydir/sqlite3-freebsd-captive/sqlite";
}

my $g_dbfile = '/home/om/public_html/dbdir/svndb';
create_table('nodes');
create_table('parentage');
# my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","","");


my @branches = map {chomp; $_} <STDIN>;

my $S = 'https://svl-svn.juniper.net/svn/junos-2009';
my $Q = 'https://svl-svn.juniper.net/svn/qf';
my $P = 'http://pkg.dcbg.juniper.net/repo/sfc';

my $done_parentage = {};
my $done_merges = {};


for my $branch (@branches) {
    print_parentage($branch);
    print_merges($branch);
}

#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
sub print_merges
{
    my $branch = shift;
    return if (exists $done_merges->{$branch});
    my @revs = sort {$a <=> $b}
               grep {/^\d+$/}
               map {s/ .*//s; s/^r//; $_}
               `svn log -q --stop-on-copy $S/branches/$branch`;
    # '446925',
    # '448139',
    # '448205',
    # '448449',
    # '448481',
    # '448482',
    # ...

    my $r = shift @revs;
    my @mergeinfo = `svn propget svn:mergeinfo $S/branches/$branch\@$r`;
    # /branches/DEV_BORG_RLI11915_BRANCH:332648-385757*
    # /branches/DEV_CASHEW_Q4_BRANCH:382348-386519*
    # /branches/DEV_CBU_0810_BRANCH:366246-380840*
    # /branches/DEV_CBU_BROOKLYN40_2_BRANCH:389504-410525*
    # /branches/DEV_CBU_SHADOW_0211_BRANCH:395956-418848*
    # /branches/DEV_CBU_SHADOW_0810_BRANCH:374933-385847*
    # /branches/DEV_CBU_SHADOW_1110_BRANCH:385222-397804*
    # /branches/DEV_CBU_SHADOW_RLI_13292_BRANCH:396249-414264*
    # /branches/DEV_EX_1001_DOUBLECAP_BRANCH:355357-374628*,390849-395396*
    # /branches/DEV_JBUILD_20100803_BRANCH:392347-406836,406985,407346
    # ...

    my $old_mergeinfo_hash = {};

    %{$old_mergeinfo_hash} = map {$_ => 1}
                             grep {$_ !~ /:$/}
                             map { simplify_mergeinfo($_) } @mergeinfo;
    # /branches/DEV_BORG_RLI11915_BRANCH:385757 => 1
    # /branches/DEV_CASHEW_Q4_BRANCH:386519 => 1
    # /branches/DEV_CBU_0810_BRANCH:380840 => 1
    # /branches/DEV_CBU_BROOKLYN40_2_BRANCH:410525 => 1
    # /branches/DEV_CBU_SHADOW_0211_BRANCH:418848 => 1
    # /branches/DEV_CBU_SHADOW_0810_BRANCH:385847 => 1
    # /branches/DEV_CBU_SHADOW_1110_BRANCH:397804 => 1
    # /branches/DEV_CBU_SHADOW_RLI_13292_BRANCH:414264 => 1
    # /branches/DEV_EX_1001_DOUBLECAP_BRANCH:395396 => 1
    # /branches/DEV_JBUILD_20100803_BRANCH:406836 => 1
    # ...

    for my $newrev (@revs) {
        @mergeinfo = `svn propget svn:mergeinfo $S/branches/$branch\@$newrev`;
        my $new_mergeinfo_hash = {};
        %{$new_mergeinfo_hash} = map {$_ => 1}
                                 grep {$_ !~ /:$/}
                                 map { simplify_mergeinfo($_) } @mergeinfo;
        my @diffpl = ();
        for my $pl (keys %{$new_mergeinfo_hash}) {
            if (! exists $old_mergeinfo_hash->{$pl}) {
                push @diffpl, $pl;
            }
        }

        @diffpl = sort largest_rev_first @diffpl;
        if (scalar @diffpl) {
            my ($from_branch, $rev, $date) = get_revinfo($diffpl[0]);
            if ($from_branch ne '') {
                print "{\n"
                    . "$from_branch\n"
                    . "$rev|$date\n"
                    . "}\n\n"
                    . "merges {\n"
                    . "$from_branch\@$rev -> $branch\@$newrev\n"
                    . "}\n\n";
                print_parentage($from_branch, $rev);
            }
        }
        undef $old_mergeinfo_hash;
        $old_mergeinfo_hash = $new_mergeinfo_hash;
    } 
    $done_merges->{$branch} = 1;
}

#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
sub simplify_mergeinfo
{
    my $mergeinfo_line = shift;
    my $branchpath = '';
    my $revs;
    if ($_ =~ m{^(/branches/[^/]+):([\d\-\,\*]+)}) {
        ($branchpath, $revs) = ($1, $2);
    }
    elsif ($_ =~ m{^(/trunk):([\d\-\,\*]+)}) {
        ($branchpath, $revs) = ($1, $2);
    }
    my @lastrevs = $revs =~ m{\-(\d+)}g;
    @lastrevs = sort {$b <=> $a} @lastrevs;
    my $largest_rev = $lastrevs[0];
    return "$branchpath:$largest_rev";
}

#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
sub get_revinfo
{
    my $pldiff = shift;
    # /branches/PR_BRANCH:449018

    # /branches/abc:12345
    # /trunk:12345

    my ($branch, $rev, $date);
    my @svninfo;
    if ($pldiff =~ m{^/branches/([^/]+):(\d+)}) {
        ($branch, $rev) = ($1, $2);
        @svninfo = `svn info $S/branches/$branch\@$rev`;
    }
    elsif ($pldiff =~ m{^/(trunk):(\d+)}) {
        ($branch, $rev) = ($1, $2);
        @svninfo = `svn info $S/trunk\@$rev`;
    }

    # 0  Path: PR_BRANCH
    # 1  URL: https://svl-svn.juniper.net/svn/junos-2009/branches/PR_BRANCH
    # 2  Repository Root: https://svl-svn.juniper.net/svn/junos-2009
    # 3  Repository UUID: af97b9c9-8f30-47ec-ba46-ed83efb130c1
    # 4  Revision: 449018
    # 5  Node Kind: directory
    # 6  Last Changed Author: ib-builder
    # 7  Last Changed Rev: 449013
    # 8  Last Changed Date: 2011-06-17 08:51:48 -0700 (Fri, 17 Jun 2011)
    ($rev)  = $svninfo[7] =~ /(\d+)\n$/s;
    ($date) = $svninfo[8] =~ /: (.+) \(/;
    return ($branch, $rev, $date);
}

#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
sub largest_rev_first
{
    my ($aa) = $a =~ /(\d+)$/;
    my ($bb) = $b =~ /(\d+)$/;
    $bb <=> $aa;
}

#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
sub print_parentage
{
    my ($branch, $inrev) = @_;
    if ($inrev eq '') {
        $inrev = 'HEAD';
    }

    return if($branch eq 'trunk');
    return if(exists $done_parentage->{$branch});
    my ($parent_branch,
        $parent_rev,
        $parent_rev_date,
        $my_rev,
        $my_rev_date) = get_origin($branch, $inrev);
    print "{\n"
        . "$branch\n"
        . "$my_rev|$my_rev_date\n"
        . "}\n\n"
        . "{\n"
        . "$parent_branch\n"
        . "$parent_rev|$parent_rev_date\n"
        . "}\n\n"
        . "parentage {\n"
        . "$parent_rev -> $branch\n"
        . "}\n\n";
    $done_parentage->{$branch} = 1;
    print_parentage($parent_branch, $parent_rev);
}

#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
sub get_origin
{
    my ($branch, $inrev) = @_;
    my @origin = ();;
    # $parent_branch
    # $parent_rev
    # $parent_rev_date
    # $my_rev
    # $my_rev_date

    @origin = get_origin_sqlite($branch, $inrev);
    if ($origin[0] eq '') {
        @origin = get_origin_svn($branch, $inrev);
    }
    return @origin;
}

#
# -------------------------------------------------------------------------
# Output format:
#     $parent_branch
#     $parent_rev
#     $parent_rev_date
#     $my_rev
#     $my_rev_date
# -------------------------------------------------------------------------
sub get_origin_sqlite
{
    my ($branch, $inrev) = @_;
    return if($branch eq 'trunk');

    my ($cmd, $output);
    $cmd = "SELECT branch,parentbranch,parentrev,myrev FROM parentage WHERE branch = \"$branch\";";
    $cmd = "echo '$cmd' | $sqlite $g_dbfile";
    $output = `$cmd`;
    chomp $output;
    if ($output eq '') {
        return ();
    }
    my ($branch,$parentbranch,$parentrev,$myrev) = split /\|/, $output;

    $cmd = "SELECT date FROM nodes WHERE n = \"$parentrev\";";
    $cmd = "echo '$cmd' | $sqlite $g_dbfile";
    my $parent_rev_date = `$cmd`;
    chomp $parent_rev_date;

    $cmd = "SELECT date FROM nodes WHERE n = \"$myrev\";";
    $cmd = "echo '$cmd' | $sqlite $g_dbfile";
    my $my_rev_date = `$cmd`;
    chomp $my_rev_date;

    return ($parentbranch,$parentrev,$parent_rev_date,$myrev,$my_rev_date);
}

#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
sub get_origin_svn
{
    my ($branch, $inrev) = @_;
    return if($branch eq 'trunk');

    if ($inrev eq '') {
        $inrev = 'HEAD';
    }


    my $cmd = "svn log --limit 1 --stop-on-copy -v -r 1:$inrev $S/branches/$branch\@$inrev";
    my @log = `$cmd`;
    # 0  ------------------------------------------------------------------------
    # 1  r446925 | ib-builder | 2011-06-08 12:10:09 -0700 (Wed, 08 Jun 2011) | 12 lines
    # 2  Changed paths:
    # 3     A /branches/DEV_X_113_FX_BRANCH (from /branches/RELEASE_113_THROTTLE:446722)
    # 4  
    # 5  PR: 661140
    # 6  Reviewed by: prao
    # 7  
    # 8  Decsription:
    # 9  DEV_X_113_FX_BRANCH is being created from RELEASE_113_THROTTLE@446722,/volume/build/junos/11.3/production/20110608.0
    # 10  
    # 11  Command used:
    # 12  svn cp $S/branches/RELEASE_113_THROTTLE@446722 $S/branches/DEV_X_113_FX_BRANCH -F DEV_X_113_FX_BRANCH_pull.txt  > DEV_X_113_FX_BRANCH_pull.log
    # 13  
    # 14  --------------------
    # 15  Refer builder request :/builder/98329
    # 16  
    # 17  ------------------------------------------------------------------------


    # 1  r446925 | ib-builder | 2011-06-08 12:10:09 -0700 (Wed, 08 Jun 2011) | 12 lines
    my ($branch_creation_rev, $branch_creation_rev_date);
    if ($log[1] =~ /^r(\d+)\s*\|\s*.*?\|\s*(.+?)\s*\(/) {
        ($branch_creation_rev, $branch_creation_rev_date) = ($1, $2);
    }
    else {
        print "Error: Cannot get branch creation rev and date\n";
        print Dumper(\@log);
        print "cmd : $cmd\n";
        next;
    }

    my $parentage_log_line;
    # 3     A /branches/DEV_X_113_FX_BRANCH (from /branches/RELEASE_113_THROTTLE:446722)
    if ($log[3] =~ /^\s+A /) {
        $parentage_log_line = $log[3];
    }
    elsif ($log[4] =~ /^\s+A /) {
        $parentage_log_line = $log[4];
    }
    else {
        return;
    }

    if ($parentage_log_line =~ m{\(from (.+):(\d+)\)\n$}s) {
        my ($parent_branch_path, $parent_rev) = ($1, $2);
        # /branches/RELEASE_113_THROTTLE  446722

        my @info = `svn info $S$parent_branch_path\@$parent_rev`;
        # % svn info $S/branches/RELEASE_113_THROTTLE@446722
        # 0  Path: RELEASE_113_THROTTLE
        # 1  URL: https://svl-svn.juniper.net/svn/junos-2009/branches/RELEASE_113_THROTTLE
        # 2  Repository Root: https://svl-svn.juniper.net/svn/junos-2009
        # 3  Repository UUID: af97b9c9-8f30-47ec-ba46-ed83efb130c1
        # 4  Revision: 446722
        # 5  Node Kind: directory
        # 6  Last Changed Author: phegde
        # 7  Last Changed Rev: 446722
        # 8  Last Changed Date: 2011-06-07 17:13:21 -0700 (Tue, 07 Jun 2011)

        my $parent_branch;
        if ($info[0] =~ /^Path: (.+)\n$/s) {
            $parent_branch = $1;
        }
        else {
            print "Error: Cannot get 'Path:'\n";
            return;
        }

        if ($info[7] =~ /^Last Changed Rev: (\d+)/) {
            $parent_rev = $1;
        }
        else {
            print "Error: Cannot get 'Last Changed Rev'\n";
            return;
        }

        my $date;
        if ($info[8] =~ /^Last Changed Date: (.+?)\s+\(/) {
            $date = $1;
        }
        else {
            print "Error: Cannot get 'Last Changed Date'\n";
            return;
        }

        my $sql;

        undef $sql;
        $sql->{n}      = $branch_creation_rev;
        $sql->{branch} = $branch;
        $sql->{date}   = $branch_creation_rev_date;
        sqlite_add_row('nodes', $sql);

        undef $sql;
        $sql->{n}      = $parent_rev;
        $sql->{branch} = $parent_branch;
        $sql->{date}   = $date;
        sqlite_add_row('nodes', $sql);

        undef $sql;
        $sql->{branch}       = $branch;
        $sql->{parentbranch} = $parent_branch;
        $sql->{parentrev}    = $parent_rev;
        $sql->{myrev}        = $branch_creation_rev;
        sqlite_add_row('parentage', $sql);

        return(
                $parent_branch,
                $parent_rev,
                $date,
                $branch_creation_rev,
                $branch_creation_rev_date
              );
    }
    else {
        print "\nError: cannot process $branch\n\n";
        return;
    }
}

#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
{
my $table_exists;

sub create_table
{
    my ($table_name) = @_;
    my $cmd = "echo '.schema $table_name' | $sqlite $g_dbfile";
    my $output = `$cmd`;
    if($output ne "") {
        $table_exists->{$table_name} = 1;
        return;
    }

    my $command = {
                    'nodes'      => 'CREATE TABLE nodes (n INTEGER PRIMARY KEY NOT NULL, date TEXT, branch TEXT);',
                    'parentage'  => 'CREATE TABLE parentage (branch TEXT PRIMARY KEY NOT NULL, parentbranch TEXT, parentrev INTEGER, myrev INTEGER);',
                  };
    unless (exists $command->{$table_name}) {
        die "Error: Don't know how to create table $table_name\n";
    }
    open CMD, "|$sqlite $g_dbfile" or die;
    print CMD $command->{$table_name};
    close CMD;

    $table_exists->{$table_name} = 1;;
}

sub sqlite_add_row
{
    my ($table_name, $things) = @_;

    unless (defined $table_exists) {
        $table_exists = {};
    }
    unless (exists $table_exists->{$table_name}) {
        create_table($table_name);
    }

    my @keys   = ();
    my @values = ();
    for my $column_name (keys %$things) {
        push @keys, $column_name;
        push @values, $things->{$column_name};
    }
    my $keys   = join ', ', map {s/^(.+)$/'$1'/; $_} @keys;
    my $values = join ', ', map {s/^(.+)$/'$1'/; $_} @values;
    my $sql_cmd = "INSERT INTO $table_name ( $keys ) VALUES ( $values );\n";
    open CMD, "|$sqlite $g_dbfile" or die;
    print CMD $sql_cmd;
    close CMD;
}
}



